const Earcut = require("./earcut");


let ToolType = {
    None: 0,
    Side: 1,
    Center: 2
};

class PointHandle {
    handle = null; //svg;
    text = null;
    ind = 0;
    pt = cc.v2();
    constructor(handle, text, ind, pt) {
        this.handle = handle;
        this.text = text;
        this.ind = ind;
        this.pt = pt;
    }
    plot(gizmo) {
        let pt = Editor.GizmosUtils.snapPixelWihVec2(this.pt);
        this.handle.move(pt.x, pt.y);
        this.handle.radius(15);
        this.text.move(pt.x - 25, pt.y - 25);
    }
};

class MyMeshGizmo extends Editor.Gizmo {
    init() {
        cc.log("MyMeshGizmo")
        // 初始化一些参数
    }
    onCreateMoveCallbacks() {
        // 创建 gizmo 操作回调
        let startV2;        // 按下鼠标时记录的圆偏移量

        return {
            /**
             * 在 gizmo 上按下鼠标时触发
             * @param x 按下点的 x 坐标
             * @param y 按下点的 y 坐标
             * @param event mousedown dom event
             */
            start: (x, y, event, ind) => {
                startV2 = this.target.polygon[ind];
            },

            /**
             * 在 gizmo 上按下鼠标移动时触发
             * @param dx 鼠标移动的 x 位移
             * @param dy 鼠标移动的 y 位移
             * @param event mousedown dom event
             */
            update: (dx, dy, event, ind) => {
                let position = this.node.convertToWorldSpaceAR(cc.Vec2.ZERO);

                // 获取 gizmo 依附的节点
                let node = this.node;
                // 获取 gizmo 依附的组件
                let target = this.target;

                // 计算新的偏移量
                let mat4 = new cc.Mat4();
                node.getWorldMatrix(mat4);
                let t = cc.Mat4.invert(mat4, mat4);
                t.m12 = t.m13 = 0;

                let d = cc.v2(dx, dy);
                cc.Vec2.transformMat4(d, d, t);
                d.addSelf(startV2);
                target.polygon[ind] = d;
                target.polygonDirty = true;
                // target._updateMaterial();
                this.handles[ind].pt = this.worldToPixel(position.add(target.polygon[ind]));
                this.handles[ind].plot(this);

                // this.adjustValue(target, 'handles');
            },

            /**
             * 在 gizmo 抬起鼠标时触发
             * @param event mousedown dom event
             */
            end: (updated, event) => {
            }
        };
    }
    handles = [];
    tris = {};
    addHandle(pt) {
        let svg = this.tool.circle()
            // 设置 fill 样式
            .fill({ color: 'rgba(255,255,255,0.2)' })
            // 设置点击区域，这里设置的是根据 fill 模式点击
            .style('pointer-events', 'fill')
            // 设置鼠标样式
            .style('cursor', 'move')
            ;
        let text = this.tool.plain(`${this.handles.length}`)
            // 设置 fill 样式
            .fill({ color: 'rgba(255,255,255,1)' })
            ;
        this.registerMoveSvg(svg, this.handles.length, { cursor: 'move' });

        let handle = new PointHandle(svg, text, this.handles.length, pt)
        this.handles.push(handle);

        handle.pt = pt;
        handle.plot(this);
    }
    onCreateRoot() {
        // 创建 svg 根节点的回调，可以在这里创建你的 svg 工具
        // this._root 可以获取到 Editor.Gizmo 创建的 svg 根节点

        // 实例：

        // 创建一个 svg 工具
        // group 函数文档：http://documentup.com/wout/svg.js#groups
        this.tool = this._root.group();
    }
    onUpdate() {
        // 获取 gizmo 依附的组件
        let target = this.target;

        this.handles.forEach(handle => {
            handle.handle.remove();
            handle.text.remove();
        });
        this.handles = [];

        for (let key in this.tris) {
            this.tris[key].remove();
        }
        this.tris = {};

        // 获取 gizmo 依附的节点
        let node = this.node;

        // 获取节点世界坐标
        let position = node.convertToWorldSpaceAR(cc.Vec2.ZERO);
        let i = 0;
        for (i = 0; i < target.polygon.length; i++) {
            let v2 = target.polygon[i];
            let pt = this.worldToPixel(position.add(v2));

            if (this.handles[i]) {
                this.handles[i].pt = pt;
                this.handles[i].plot(this);
            }
            else {
                this.addHandle(pt);
            }
        }

        // 定义顶点，每个顶点包含 x, y 坐标
        const vertices = [];
        this.target.polygon.forEach(v2 => {
            vertices.push(v2.x, v2.y);
        });

        // 定义洞的顶点索引（如果有的话）。在这个例子中没有洞，所以我们可以省略这一步。
        // const holes = [];
        // 使用 earcut 进行三角剖分
        let indices = Earcut.earcut(vertices /*, holes */);
        // let indices = SplitePolygon(this.target.polygon);

        let triKeys = Object.keys(this.tris);
        // 根据索引绘制三角形
        for (let i = 0; i < indices.length; i += 3) {
            const p1 = this.handles[indices[i]].pt;
            const p2 = this.handles[indices[i + 1]].pt;
            const p3 = this.handles[indices[i + 2]].pt;

            let triKey = `${indices[i]}-${indices[i + 1]}-${indices[i + 2]}`;
            let path = this.tris[triKey];
            if (!path) {
                path = this.tool.path(`M${p1.x},${p1.y} L${p2.x},${p2.y} L${p3.x},${p3.y} Z`).fill('none').stroke({ width: 1, color: '#FFF' });
                this.tris[triKey] = path;
            }
            else {
                triKeys.splice(triKeys.findIndex(ele => ele === triKey), 1);
            }
            // 更新路径
            path.plot(`M${p1.x},${p1.y} L${p2.x},${p2.y} L${p3.x},${p3.y} Z`);

        }

        triKeys.forEach(key => {
            this.tris[key].remove();
            delete this.tris[key];
        });

        this.target.indices = indices
        // // 转换世界坐标到 svg view 上
        // // svg view 的坐标体系和节点坐标体系不太一样，这里使用内置函数来转换坐标
        // position = this.worldToPixel(position);

        // // 对齐坐标，防止 svg 因为精度问题产生抖动
        // position = Editor.GizmosUtils.snapPixelWihVec2(position);

        // // 获取世界坐标下圆半径
        // let p1 = node.convertToWorldSpaceAR(cc.v2(target.radius, 0));
        // let p2 = node.convertToWorldSpaceAR(cc.v2(0, 0));
        // let radius = p1.sub(p2).mag();

        // // 对齐坐标，防止 svg 因为精度问题产生抖动
        // radius = Editor.GizmosUtils.snapPixel(radius);

        // // 移动 svg 工具到坐标
        // this._tool.plot(radius, position);
    }

    // 如果需要自定义 Gizmo 显示的时机，重写 visible 函数即可
    //    visible () {
    //        return this.selecting || this.editing;
    //    }

    // Gizmo 创建在哪个 Layer 中：foreground, scene, background
    // 默认创建在 scene Layer
    //    layer () {
    //        return 'scene';
    //    }

    // 如果 Gizmo 需要参加点击测试，重写 rectHitTest 函数即可
    //    rectHitTest (rect, testRectContains) {
    //        return false;
    //    }
}

module.exports = MyMeshGizmo;


// 判断一个点是否在三角形内
const IsInTriangle = function (point , triA, triB, triC) {
    let AB = triB.sub(triA), AC = triC.sub(triA), BC = triC.sub(triB), AD = point.sub(triA), BD = point.sub(triB);
    //@ts-ignore
    return (AB.cross(AC) >= 0 ^ AB.cross(AD) < 0) && (AB.cross(AC) >= 0 ^ AC.cross(AD) >= 0) && (BC.cross(AB) > 0 ^ BC.cross(BD) >= 0);
}

// 多边形 三角切割
const SplitePolygon = function (points) {
    if (points.length <= 3) return [0, 1, 2];
    let pointMap = {};     // point与idx的映射
    for (let i = 0; i < points.length; i++) {
        let p = points[i];
        pointMap[`${p.x}-${p.y}`] = i;
    }
    const getIdx = (p) => {
        return pointMap[`${p.x}-${p.y}`]
    }
    points = points.concat([]);
    let idxs = [];

    let index = 0;
    while (points.length > 3) {
        let p1 = points[(index) % points.length]
            , p2 = points[(index + 1) % points.length]
            , p3 = points[(index + 2) % points.length];
        let splitPoint = (index + 1) % points.length;

        let v1 = p2.sub(p1);
        let v2 = p3.sub(p2);
        if (v1.cross(v2) < 0) {      // 是一个凹角, 寻找下一个
            index = (index + 1) % points.length;
            continue;
        }
        let hasPoint = false;
        for (const p of points) {
            if (p != p1 && p != p2 && p != p3 && IsInTriangle(p, p1, p2, p3)) {
                hasPoint = true;
                break;
            }
        }
        if (hasPoint) {      // 当前三角形包含其他点, 寻找下一个
            index = (index + 1) % points.length;
            continue;
        }
        // 找到了耳朵, 切掉
        idxs.push(getIdx(p1), getIdx(p2), getIdx(p3));
        points.splice(splitPoint, 1);
    }
    for (const p of points) {
        idxs.push(getIdx(p));
    }
    return idxs;
}
// let ToolType = {
//     None: 0,
//     Side: 1,
//     Center: 2
// };


// class MyMeshGizmo extends Editor.Gizmo {
//     init() {
//         // 初始化一些参数
//     }
//     onCreateMoveCallbacks() {
//         // 创建 gizmo 操作回调

//         // 申明一些局部变量
//         let startOffset;        // 按下鼠标时记录的圆偏移量
//         let startRadius;        // 按下鼠标时记录的圆半径
//         let pressx, pressy;     // 按下鼠标时记录的鼠标位置

//         return {
//             /**
//              * 在 gizmo 上按下鼠标时触发
//              * @param x 按下点的 x 坐标
//              * @param y 按下点的 y 坐标
//              * @param event mousedown dom event
//              */
//             start: (x, y, event) => {
//                 startRadius = this.target.radius;
//                 startOffset = this.target.offset;
//                 pressx = x;
//                 pressy = y;
//             },

//             /**
//              * 在 gizmo 上按下鼠标移动时触发
//              * @param dx 鼠标移动的 x 位移
//              * @param dy 鼠标移动的 y 位移
//              * @param event mousedown dom event
//              */
//             update: (dx, dy, event, type) => {
//                 // 获取 gizmo 依附的节点
//                 let node = this.node;

//                 // 获取 gizmo 依附的组件
//                 let target = this.target;

//                 if (type === ToolType.Center) {
//                     // 计算新的偏移量
//                     let mat4 = new cc.Mat4();
//                     node.getWorldMatrix(mat4);
//                     let t = cc.Mat4.invert(mat4, mat4);
//                     t.m12 = t.m13 = 0;

//                     let d = cc.v2(dx, dy);
//                     cc.Vec2.transformMat4(d, d, t);
//                     d.addSelf(startOffset);
//                     target.offset = d;
//                     this.adjustValue(target, 'offset');
//                 }
//                 else {
//                     // 转换坐标点到节点下
//                     let position = node.convertToNodeSpaceAR(cc.v2(pressx + dx, pressy + dy));
//                     // 计算 radius
//                     target.radius = position.sub(startOffset).mag();
//                     // 防止 radius 小数点位数过多
//                     this.adjustValue(target, 'radius');
//                 }
//             },

//             /**
//              * 在 gizmo 抬起鼠标时触发
//              * @param event mousedown dom event
//              */
//             end: (updated, event) => {
//             }
//         };
//     }

//     onCreateRoot() {
//         // 创建 svg 根节点的回调，可以在这里创建你的 svg 工具
//         // this._root 可以获取到 Editor.Gizmo 创建的 svg 根节点

//         // 实例：

//         // 创建一个 svg 工具
//         // group 函数文档：http://documentup.com/wout/svg.js#groups
//         this._tool = this._root.group();

//         // 创建中心拖拽区域，用于操作 offset 属性
//         let dragArea = this._tool.circle()
//             // 设置 fill 样式
//             .fill({ color: 'rgba(0,128,255,0.2)' })
//             // 设置点击区域，这里设置的是根据 fill 模式点击
//             .style('pointer-events', 'fill')
//             // 设置鼠标样式
//             .style('cursor', 'move')
//             ;

//         // 注册监听鼠标移动事件的 svg 元素
//         // ToolType.Center 是自定义的参数，会在移动回调中按照参数的形式传递到移动回调中，方便区别当前回调是哪一个 svg 元素产生的回调。
//         // {cursor: 'move'} 指定移动时的鼠标类型
//         this.registerMoveSvg(dragArea, ToolType.Center, { cursor: 'move' });

//         // 创建边缘拖拽区域，用于操作 radius 属性
//         let circle = this._tool.circle()
//             // 设置stroke 样式
//             .stroke({ color: '#7fc97a', width: 2 })
//             // 设置点击区域，这里设置的是根据 stroke 模式点击
//             .style('pointer-events', 'stroke')
//             // 设置鼠标样式
//             .style('cursor', 'pointer')

//         this.registerMoveSvg(circle, ToolType.Side, { cursor: 'pointer' });

//         // 为 tool 定义一个绘画函数，方便在 onUpdate 中更新 svg 的绘制。
//         this._tool.plot = (radius, position) => {
//             this._tool.move(position.x, position.y);
//             dragArea.radius(radius);
//             circle.radius(radius);
//         };
//     }

//     onUpdate() {
//         // 更新 svg 工具

//         // 获取 gizmo 依附的组件
//         let target = this.target;

//         // 获取 gizmo 依附的节点
//         let node = this.node;

//         // 获取节点世界坐标
//         let position = node.convertToWorldSpaceAR(target.offset);

//         target.polygon.forEach(v2 => {
//             let pt = this.worldToPixel(position.add(v2));
//             pt = Editor.GizmosUtils.snapPixelWihVec2(pt);
//             this._tool.plot(5, pt);
//         });

//         // // 转换世界坐标到 svg view 上
//         // // svg view 的坐标体系和节点坐标体系不太一样，这里使用内置函数来转换坐标
//         // position = this.worldToPixel(position);

//         // // 对齐坐标，防止 svg 因为精度问题产生抖动
//         // position = Editor.GizmosUtils.snapPixelWihVec2(position);

//         // // 获取世界坐标下圆半径
//         // let p1 = node.convertToWorldSpaceAR(cc.v2(target.radius, 0));
//         // let p2 = node.convertToWorldSpaceAR(cc.v2(0, 0));
//         // let radius = p1.sub(p2).mag();

//         // // 对齐坐标，防止 svg 因为精度问题产生抖动
//         // radius = Editor.GizmosUtils.snapPixel(radius);

//         // // 移动 svg 工具到坐标
//         // this._tool.plot(radius, position);
//     }

//     // 如果需要自定义 Gizmo 显示的时机，重写 visible 函数即可
//     //    visible () {
//     //        return this.selecting || this.editing;
//     //    }

//     // Gizmo 创建在哪个 Layer 中：foreground, scene, background
//     // 默认创建在 scene Layer
//     //    layer () {
//     //        return 'scene';
//     //    }

//     // 如果 Gizmo 需要参加点击测试，重写 rectHitTest 函数即可
//     //    rectHitTest (rect, testRectContains) {
//     //        return false;
//     //    }
// }

// module.exports = MyMeshGizmo;